package heap

import "strings"

type MethodDescriptorParser struct {
	Raw    string
	Offset int
	Parsed *MethodDescriptor
}

func parseMethodDescriptor(descriptor string) *MethodDescriptor {
	parser := &MethodDescriptorParser{}
	return parser.parse(descriptor)
}

/*
Method的Descriptor格式：
(fieldType|)
 */
func (self *MethodDescriptorParser) parse(descriptor string) *MethodDescriptor {
	self.Raw = descriptor
	self.Parsed = &MethodDescriptor{}
	self.startParams()
	self.parseParamTypes()
	self.endParams()
	self.parseReturnType()
	self.finish()
	return self.Parsed
}

func (self *MethodDescriptorParser) startParams() {
	if self.readUint8() != '(' {
		self.causePanic()
	}
}
func (self *MethodDescriptorParser) endParams() {
	if self.readUint8() != ')' {
		self.causePanic()
	}
}
func (self *MethodDescriptorParser) finish() {
	if self.Offset != len(self.Raw) {
		self.causePanic()
	}
}

func (self *MethodDescriptorParser) causePanic() {
	panic("BAD descriptor: " + self.Raw)
}

func (self *MethodDescriptorParser) readUint8() uint8 {
	b := self.Raw[self.Offset]
	self.Offset++
	return b
}
func (self *MethodDescriptorParser) unreadUint8() {
	self.Offset--
}

// 循环独处所有数据类型，并push到Parsed中
func (self *MethodDescriptorParser) parseParamTypes() {
	for {
		t := self.parseFieldType()
		if t != "" {
			self.Parsed.pushParameterType(t)
		} else {
			break
		}
	}
}

func (self *MethodDescriptorParser) parseReturnType() {
	if self.readUint8() == 'V' {
		self.Parsed.ReturnType = "V"
		return
	}

	self.unreadUint8()
	t := self.parseFieldType()
	if t != "" {
		self.Parsed.ReturnType = t
		return
	}

	self.causePanic()
}

// 读取下一个属性类型
func (self *MethodDescriptorParser) parseFieldType() string {
	switch self.readUint8() {
	case 'B':
		return "B"
	case 'C':
		return "C"
	case 'D':
		return "D"
	case 'F':
		return "F"
	case 'I':
		return "I"
	case 'J':
		return "J"
	case 'S':
		return "S"
	case 'Z':
		return "Z"
	case 'L':
		return self.parseObjectType()
	case '[':
		return self.parseArrayType()
	default:
		self.unreadUint8()
		return ""
	}
}

// 读取数据类型： 该类型为字符串
// 从Offset开始，到下一个;位置，返回的是一个类型
// 如果没有找到;，则返回异常
func (self *MethodDescriptorParser) parseObjectType() string {
	unread := self.Raw[self.Offset:]
	semicolonIndex := strings.IndexRune(unread, ';')
	if semicolonIndex == -1 {
		self.causePanic()
		return ""
	} else {
		return readStringFromRaw(self, semicolonIndex)
	}
}

// 读取数据类型字符串
func readStringFromRaw(parser *MethodDescriptorParser, semicolonIndex int) string {
	objStart := parser.Offset - 1
	objEnd := parser.Offset + semicolonIndex + 1
	parser.Offset = objEnd
	descriptor := parser.Raw[objStart:objEnd]
	return descriptor
}

func (self *MethodDescriptorParser) parseArrayType() string {
	arrStart := self.Offset - 1
	self.parseFieldType()
	arrEnd := self.Offset
	descriptor := self.Raw[arrStart:arrEnd]
	return descriptor
}
